#include<iostream>
#include<string>
#include<vector>
using namespace std;
int IP[] = { 58, 50, 42, 34, 26, 18, 10, 2,
			 60, 52, 44, 36, 28, 20, 12, 4,
			 62, 54, 46, 38, 30, 22, 14, 6,
			 64, 56, 48, 40, 32, 24, 16, 8,
			 57, 49, 41, 33, 25, 17, 9,  1,
			 59, 51, 43, 35, 27, 19, 11, 3,
			 61, 53, 45, 37, 29, 21, 13, 5,
			 63, 55, 47, 39, 31, 23, 15, 7 };
int IPR[] = { 40, 8, 48, 16, 56, 24, 64, 32,
			  39, 7, 47, 15, 55, 23, 63, 31,
			  38, 6, 46, 14, 54, 22, 62, 30,
			  37, 5, 45, 13, 53, 21, 61, 29,
			  36, 4, 44, 12, 52, 20, 60, 28,
			  35, 3, 43, 11, 51, 19, 59, 27,
			  34, 2, 42, 10, 50, 18, 58, 26,
			  33, 1, 41,  9, 49, 17, 57, 25 };
int PC1[] = { 57, 49, 41, 33, 25, 17, 9,
			   1, 58, 50, 42, 34, 26, 18,
			  10,  2, 59, 51, 43, 35, 27,
			  19, 11,  3, 60, 52, 44, 36,
			  63, 55, 47, 39, 31, 23, 15,
			   7, 62, 54, 46, 38, 30, 22,
			  14,  6, 61, 53, 45, 37, 29,
			  21, 13,  5, 28, 20, 12,  4 };
int PC2[] = { 14, 17, 11, 24,  1,  5,
			   3, 28, 15,  6, 21, 10,
			  23, 19, 12,  4, 26,  8,
			  16,  7, 27, 20, 13,  2,
			  41, 52, 31, 37, 47, 55,
			  30, 40, 51, 45, 33, 48,
			  44, 49, 39, 56, 34, 53,
			  46, 42, 50, 36, 29, 32 };
int LS[] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
int E[] = { 32,  1,  2,  3,  4,  5,
			4,  5,  6,  7,  8,  9,
			8,  9, 10, 11, 12, 13,
			12, 13, 14, 15, 16, 17,
			16, 17, 18, 19, 20, 21,
			20, 21, 22, 23, 24, 25,
			24, 25, 26, 27, 28, 29,
			28, 29, 30, 31, 32,  1 };
int SBOX[8][4][16] = {
	{{14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7},
	 {0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8},
	 {4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0},
	 {15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13}},
	{{15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10},
	 {3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5},
	 {0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15},
	 {13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9}},
	{{10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8},
	 {13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1},
	 {13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7},
	 {1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12}},
	{{7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15},
	 {13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9},
	 {10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4},
	 {3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14}},
	{{2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9},
	 {14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6},
	 {4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14},
	 {11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3}},
	{{12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11},
	 {10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8},
	 {9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6},
	 {4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13}},
	{{4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1},
	 {13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6},
	 {1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2},
	 {6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12}},
	{{13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7},
	 {1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2},
	 {7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8},
	 {2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11}}
};
int P[] = { 16,  7, 20, 21,
			29, 12, 28, 17,
			1, 15, 23, 26,
			5, 18, 31, 10,
			2,  8, 24, 14,
			32, 27, 3,  9,
			19, 13, 30, 6,
			22, 11,  4, 25 };
bool is_encode = true;
vector<string> v;
static const struct des_test_case {
	int num, mode; // mode 1 = encrypt
	unsigned char key[8], txt[8], out[8];
} cases[] = {
	{ 1, 1,     { 0x10, 0x31, 0x6E, 0x02, 0x8C, 0x8F, 0x3B, 0x4A },
				{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
				{ 0x82, 0xDC, 0xBA, 0xFB, 0xDE, 0xAB, 0x66, 0x02 } },
	{ 2, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00 },
				{ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
	{ 3, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0xDD, 0x7F, 0x12, 0x1C, 0xA5, 0x01, 0x56, 0x19 },
				{ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
	{ 4, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x2E, 0x86, 0x53, 0x10, 0x4F, 0x38, 0x34, 0xEA },
				{ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
	{ 5, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x4B, 0xD3, 0x88, 0xFF, 0x6C, 0xD8, 0x1D, 0x4F },
				{ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
	{ 6, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x20, 0xB9, 0xE7, 0x67, 0xB2, 0xFB, 0x14, 0x56 },
				{ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
	{ 7, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x55, 0x57, 0x93, 0x80, 0xD7, 0x71, 0x38, 0xEF },
				{ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
	{ 8, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x6C, 0xC5, 0xDE, 0xFA, 0xAF, 0x04, 0x51, 0x2F },
				{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
	{ 9, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x0D, 0x9F, 0x27, 0x9B, 0xA5, 0xD8, 0x72, 0x60 },
				{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
	{10, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0xD9, 0x03, 0x1B, 0x02, 0x71, 0xBD, 0x5A, 0x0A },
				{ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },

	{ 1, 0,     { 0x10, 0x31, 0x6E, 0x02, 0x8C, 0x8F, 0x3B, 0x4A },
				{ 0x82, 0xDC, 0xBA, 0xFB, 0xDE, 0xAB, 0x66, 0x02 },
				{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
	{ 2, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
				{ 0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00 } },
	{ 3, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
				{ 0xDD, 0x7F, 0x12, 0x1C, 0xA5, 0x01, 0x56, 0x19 } },
	{ 4, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
				{ 0x2E, 0x86, 0x53, 0x10, 0x4F, 0x38, 0x34, 0xEA } },
	{ 5, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
				{ 0x4B, 0xD3, 0x88, 0xFF, 0x6C, 0xD8, 0x1D, 0x4F } },
	{ 6, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
				{ 0x20, 0xB9, 0xE7, 0x67, 0xB2, 0xFB, 0x14, 0x56 } },
	{ 7, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
				{ 0x55, 0x57, 0x93, 0x80, 0xD7, 0x71, 0x38, 0xEF } },
	{ 8, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
				{ 0x6C, 0xC5, 0xDE, 0xFA, 0xAF, 0x04, 0x51, 0x2F } },
	{ 9, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
				{ 0x0D, 0x9F, 0x27, 0x9B, 0xA5, 0xD8, 0x72, 0x60 } },
	{10, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
				{ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
				{ 0xD9, 0x03, 0x1B, 0x02, 0x71, 0xBD, 0x5A, 0x0A } }
};
string M = "";//输入M，64位
string L = "";//输入M的左32位
string R = "";//输入M的右32位
string K = "";//密钥的输入，56位
void IP_() {//使用IP做初始置换，将明文划分为左右两部分
	for (int i = 0; i < 32; i++) {
		L += M[IP[i] - 1];
		R += M[IP[32 + i] - 1];
	}
}
string IPR_(string s) {//逆初始置换
	string res = "";
	for (int i = 0; i < 64; i++) {
		res += s[IPR[i] - 1];
	}
	return res;
}
string DEC2BIN(int a, bool flag = 0) {//十进制转2进制
	string res;
	int len;
	if (flag) {
		res = "00000000";
		len = 8;
	}
	else {
		res = "0000";
		len = 4;
	}
	for (int i = 0; i < len && a; i++) {
		if (a % 2) {
			res[len - 1 - i] = '1';
		}a /= 2;
	}
	return res;
}
string HEX2STR(const unsigned char* c) {
	string res = "";
	for (int i = 0; i < 8; i++) {
		res += DEC2BIN((int)c[i], 1);
	}
	return res;
}
string STR2HEX(string s) {
	string res = "";
	char dic[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
	for (int i = 0; i < 16; i++) {
		if (i % 2 == 0) {
			res += "0X";
		}
		int index = (s[4 * i] - '0') * 8 + (s[4 * i + 1] - '0') * 4 + (s[4 * i + 2] - '0') * 2 + (s[4 * i + 3] - '0');
		res += dic[index];
		if (i % 2) {
			res += " ";
		}
	}
	return res;
}
string E_(string r) {//选择扩展运算E，将32位r扩展为48位的res
	string res = "";
	for (int i = 0; i < 48; i++) {
		res += r[E[i] - 1];
	}
	return res;
}
string XOR(string a, string b) {
	string res = "";
	for (int i = 0; i < a.length(); i++) { res += (a[i] == b[i] ? '0' : '1'); }//如果相同就是0；不同就是1	}
	return res;
}
string S_(string s) {
	string res = "";
	for (int i = 0; i < 8; i++) {
		int row = (s[6 * i] == '1') * 2 + (s[6 * i + 5] == '1');
		int col = (s[6 * i + 1] == '1') * 8 + (s[6 * i + 2] == '1') * 4 + (s[6 * i + 3] == '1') * 2 + (s[6 * i + 4] == '1');
		res += DEC2BIN(SBOX[i][row][col]);
	}
	return res;
}
string P_(string s) {
	string res = "";
	for (int i = 0; i < 32; i++) {
		res += s[P[i] - 1];
	}
	return res;
}
string LS_(string s, int t) {//s为待处理的28位密钥，t为循环位数
	return s.substr(t) + s.substr(0, t);
}
void K_() {
	for (int i = 0; i < 16; i++) {
		string res = "";
		K = LS_(K.substr(0, 28), LS[i]) + LS_(K.substr(28, 29), LS[i]);//子密钥输入更新	
		for (int j = 0; j < 48; j++) {
			res += K[PC2[j] - 1];
		}
		v.push_back(res);
		//K_(i);//获得密钥数组v
	}
}
string F_(int i) {//F变换
	//输入参数r为右半部分r，ki为密钥输入(体现在全局变量K),i为轮数
	if (is_encode)
		return P_(S_(XOR(E_(R), v[i])));//F变换的结果	
	else
		return P_(S_(XOR(E_(R), v[15 - i])));
}
int count(string s, string t) {
	int num = 0;
	for (int i = 0; i < s.length(); i++) {
		if (s[i] != t[i])num++;
	}return num;
}
void code() {
	int begin = (is_encode) ? 0 : 10;
	int end = (is_encode) ? 10 : 20;
	for (int i = begin; i < end; i++) {
		//获取数据
		K = "";
		M = "";
		L = "";
		R = "";
		M = HEX2STR(cases[i].txt);//明文
		string K_64 = HEX2STR(cases[i].key);//64位密钥
		string C = HEX2STR(cases[i].out);//应该输出的内容
		for (int j = 0; j < 56; j++)K += K_64[PC1[j] - 1];//置换1转换为56位密钥
		IP_();//使用IP进行置换，将M分成左右两部分
		K_();
		for (int j = 0; j < 16; j++) {
			string temp = XOR(F_(j), L);
			L = R;
			R = temp;
		}
		string s = IPR_(R + L);
		if (is_encode) {
			cout << "第" << i + 1 << "组的明文序列为" << STR2HEX(M) << endl;//明文
			cout << "第" << i + 1 << "组的密文输出为" << STR2HEX(s) << endl;//我得到的密文
			cout << "第" << i + 1 << "组的密文序列为" << STR2HEX(C) << endl;//应该输出的密文
		}
		else {
			cout << "第" << i - 9 << "组的密文序列为" << STR2HEX(M) << endl;//明文
			cout << "第" << i - 9 << "组的明文输出为" << STR2HEX(s) << endl;//我得到的明文
			cout << "第" << i - 9 << "组的明文序列为" << STR2HEX(C) << endl;//应该输出的明文
		}
		v.clear();
		//改变位
		for (int change = 0; change < 8; change++) {
			K = "";
			L = "";
			R = "";
			K_64[change] = (K_64[change] == '0') ? '1' : '0';
			for (int j = 0; j < 56; j++)K += K_64[PC1[j] - 1];//置换1转换为56位密钥
			IP_();//使用IP进行置换，将M分成左右两部分
			K_();
			for (int j = 0; j < 16; j++) {
				string temp = XOR(F_(j), L);
				L = R;
				R = temp;
			}
			string t = IPR_(R + L);
			cout << "改变第" << change << "位后，有" << count(s, t) << "位发生改变。" << endl;
			//cout << count(s, t) << endl;
			v.clear();
		}
		cout << endl;
	}
}


int main() {
	cout << "请选择是加密还是解密？1------加密     0------解密" << endl;
	cout << "您的选择：";
	cin >> is_encode;
	code();
}